import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 周斌
 * Date: 2024-07-05
 * Time: 10:04
 */
public class tcpEchoServer {
    private ServerSocket serverSocket = null;

    public tcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!!!");
        ExecutorService pool = Executors.newCachedThreadPool();

        //将服务器与客户端进行连接，连接成功返回一个Socket对象，后续服务器对客户端的操作都基于这个对象
        while(true) {
            Socket clientSocket = serverSocket.accept();
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
    public void processConnection(Socket clienSocket) throws IOException {
        //打印一个客户端上线的日志
        System.out.printf("[%s:%d]客户端上线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
        //1.接收客户端发送过来的信息和并解析
        try(InputStream inputStream = clienSocket.getInputStream();
            OutputStream outputStream = clienSocket.getOutputStream()) {
            //接收客户端发送过来的请求并解析(相当于从客户端读到服务器),用到Scanner的原因是由于InputStream读取的数据是字节的形式，
            //后续处理数据的时候还是要将数据从字节形式转化为字符串，而Scanner内部可以帮我们直接转化。
            Scanner scanner = new Scanner(inputStream);
            //由于需要处理客户端不断发送过来的请求，我们就需要一个while循环
            while(true) {
                //处理客户端那边不发送请求的情况
                if(!scanner.hasNext()) {
                    System.out.printf("[%s:%d]客户端下线!\n",clienSocket.getInetAddress(),clienSocket.getPort());
                    break;
                }
                //将从客户端接收过来的数据赋值到request中，为之后处理数据做铺垫
                //这里的scanner.next()需要读到空白符才会停止，所以为了区分每一份的应用层的数据报，所以我们可以在客户端手动添加空白符，
                //来控制每一份的应用层数据报
                String request = scanner.next();
                //2.计算响应,由于这是一个回显服务器，所以我们呢不需要对响应做处理，请求什么就返回什么响应
                String response = process(request);
                //3.将计算好的响应传回客户端(相当与将数据写回客户端)
                outputStream.write(response.getBytes(),0,response.getBytes().length);
                //4.打印服务器日志
                System.out.printf("[%s:%d]res = %s,resp = %s\n",clienSocket.getInetAddress(),clienSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            clienSocket.close();
        }
    }
    public String process(String request) {
        return request + "\n";
    }

    public static void main(String[] args) throws IOException {
        tcpEchoServer server = new tcpEchoServer(9999);
        server.start();
    }
}
